﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace BaseHelper.Base
{
    public class ZipHelper
    {
        public static string Error;

        public static bool Zip(string FilePath, string Folder)
        {
            Error = "";

            if (!Directory.Exists(Folder))
            {
                Error = "目标文件夹丢失！";
                return false;
            }
            if (File.Exists(FilePath))
            {
                try
                {
                    File.Delete(FilePath);
                }
                catch (Exception ex)
                {

                }
            }

            try
            {

                string fileHeader = Scan(Folder, "");
                if (fileHeader.Length > 0)
                    fileHeader = fileHeader.Substring(0, fileHeader.Length - 1);

                byte[] zipFileName = Encoding.Default.GetBytes(Convert.ToBase64String(Encoding.Default.GetBytes(fileHeader)));
                byte[] zipHeaderLength = Encoding.ASCII.GetBytes(zipFileName.Length.ToString());
                byte[] zipHeader = new byte[10];

                Array.Copy(zipHeaderLength, 0, zipHeader, zipHeader.Length - zipHeaderLength.Length, zipHeaderLength.Length);


                Stream stream = File.OpenWrite(FilePath);
                BinaryWriter bw = new BinaryWriter(stream);
                bw.Write(zipHeader, 0, 10);
                bw.Write(zipFileName, 0, zipFileName.Length);

                string[] files = fileHeader.Split('|');

                foreach (string file in files)
                {
                    string[] sp = file.Split(',');
                    string fullName = Folder + sp[0];
                    long fileSize = Convert.ToInt64(sp[1]);

                    Stream fileStream = File.OpenRead(fullName);
                    BinaryReader fileRead = new BinaryReader(fileStream);
                    byte[] buffer = new byte[8192];
                    long blockCount = fileSize / buffer.Length;
                    int blockRemain = Convert.ToInt32(fileSize % buffer.Length);

                    for (int i = 0; i < blockCount; i++)
                    {
                        buffer = fileRead.ReadBytes(buffer.Length);
                        bw.Write(buffer, 0, buffer.Length);
                        bw.Flush();
                    }

                    if (blockRemain > 0)
                    {
                        buffer = fileRead.ReadBytes(blockRemain);
                        bw.Write(buffer, 0, buffer.Length);
                        bw.Flush();
                    }

                    fileRead.Close();
                    fileStream.Close();
                }

                bw.Close();
                stream.Close();
                return true;
            }
            catch (Exception ex)
            {
                Error = ex.Message;
                return false;
            }
        }

        private static string Scan(string ParentFolder, string Folder)
        {

            string fileHeader = "";
            DirectoryInfo dinfo = new DirectoryInfo(ParentFolder + Folder);

            foreach (FileInfo f in dinfo.GetFiles())
            {
                fileHeader += Folder + f.Name + "," + f.Length.ToString() + "|";
            }

            foreach (DirectoryInfo d in dinfo.GetDirectories())
            {
                fileHeader += Scan(ParentFolder, d.Name + "\\");
            }

            return fileHeader;
        }

        public static bool UnZip(string FilePath, string Folder)
        {
            Error = "";
            if (!File.Exists(FilePath))
            {
                Error = "目标包不存在！";
                return false;
            }
            if (!Directory.Exists(Folder))
                Directory.CreateDirectory(Folder);

            try
            {
                if (Folder.LastIndexOf("\\") != (Folder.Length - 1))
                    Folder += "\\";

                Stream stream = File.OpenRead(FilePath);
                BinaryReader br = new BinaryReader(stream);

                byte[] zipHeader = br.ReadBytes(10);
                string b = Encoding.ASCII.GetString(zipHeader).Replace("\0", "").Trim();
                int zipHeaderLength = Convert.ToInt32(b);
                byte[] zipFileName = br.ReadBytes(zipHeaderLength);

                string fileHeader = Encoding.Default.GetString(Convert.FromBase64String(Encoding.ASCII.GetString(zipFileName)));

                if (!fileHeader.Contains("|"))
                    return false;

                string[] files = fileHeader.Split('|');
                for (int i = 0; i < files.Length; i++)
                {
                    try
                    {
                        string[] sp = files[i].Split(',');
                        FileInfo finfo = new FileInfo(Folder + sp[0]);

                        if (!Directory.Exists(finfo.DirectoryName))
                            Directory.CreateDirectory(finfo.DirectoryName);

                        long fileSize = Convert.ToInt64(sp[1]);

                        if (finfo.Exists)
                        {
                            try
                            {
                                finfo.Delete();
                            }
                            catch { }
                        }

                        Stream fileStream = File.OpenWrite(finfo.FullName);
                        BinaryWriter fileWrite = new BinaryWriter(fileStream);
                        byte[] buffer = new byte[8192];
                        long blockCount = fileSize / buffer.Length;
                        int blockRemain = Convert.ToInt32(fileSize % buffer.Length);

                        for (int j = 0; j < blockCount; j++)
                        {
                            buffer = br.ReadBytes(buffer.Length);
                            fileWrite.Write(buffer, 0, buffer.Length);
                            fileWrite.Flush();
                        }

                        if (blockRemain > 0)
                        {
                            buffer = br.ReadBytes(blockRemain);
                            fileWrite.Write(buffer, 0, buffer.Length);
                            fileWrite.Flush();
                        }

                        fileWrite.Close();
                        fileStream.Close();


                    }
                    catch (Exception exx)
                    {
                        Error = exx.Message;
                        Console.WriteLine(exx.Message);
                    }
                }
                br.Close();

                return true;
            }
            catch (Exception ex)
            {
                Error = ex.Message;
                return false;
            }

        }
    }
}
